using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MongoScienceDAL.Core.Exceptions;

namespace MongoScienceDAL.Core.Tests
{
    [TestClass]
    public class ScienceRepositoryTests : MongoRepositoryTestBase
    {

        #region Create Methods

        [TestMethod]
        public void CreateMethodAddsToTheDatabase()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //get raw collection check it empty
            var mdb = TestHarness.DataSource.Database;
            var collection = mdb.GetCollection(CollectionName);
            Assert.IsTrue(collection.Count() <= 0);

            //insert
            repo.Create(data);

            //check it is full
            Assert.IsTrue(collection.Count() == 1);
        }

        [TestMethod]
        public void CreateMethodReturnsCorrectObjectId()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //get raw collection
            var mdb = TestHarness.DataSource.Database;
            var collection = mdb.GetCollection(CollectionName);

            //insert
            var objectId = repo.Create(data);

            //check the object with correct id exists
            Assert.IsTrue(collection.FindOneById(objectId) != null);
        }

        [TestMethod]
        public void CreateMethodReturnsEmptyCollectionIfNullWasPassedAsData()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //create object
            var objectId = repo.Create(null);
            
            //find object
            var scienceEntry = repo.Retrieve(objectId);

            //check the data entry is not null
            Assert.IsNotNull(scienceEntry.Data);
        }

        #endregion

        #region Retreive Methods

        [TestMethod]
        public void RetreiveRetreivesCorrectly()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //insert
            var objectId = repo.Create(data);

            //retreive!
            var newObject = repo.Retrieve(objectId);

            Assert.AreEqual(newObject.Id, objectId);
            Assert.AreEqual(newObject.Collection.Name, CollectionName);
            Assert.AreEqual(newObject.Data["t1"], data["t1"]);
            Assert.AreEqual(newObject.Data["t2"], data["t2"]);
            Assert.AreEqual(newObject.Data["t3"], data["t3"]);
        }

        #endregion

        [TestMethod]
        public void DeleteRemovesObjectSpecified()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //insert
            var objectId = repo.Create(data);

            //get raw collection check its full
            var mdb = TestHarness.DataSource.Database;
            var collection = mdb.GetCollection(CollectionName);
            Assert.IsTrue(collection.Count() == 1);

            //insert
            repo.Delete(objectId);

            //check it is full
            Assert.IsTrue(collection.Count() <= 0);
        }

        [TestMethod]
        public void UpdateUpdatesFieldsAsSpecified()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //insert
            var objectId = repo.Create(data);

            //retreive!
            var newObject = repo.Retrieve(objectId);

            //check all is as specified
            Assert.AreEqual(newObject.Id, objectId);
            Assert.AreEqual(newObject.Collection.Name, CollectionName);
            Assert.AreEqual(newObject.Data["t1"], data["t1"]);
            Assert.AreEqual(newObject.Data["t2"], data["t2"]);
            Assert.AreEqual(newObject.Data["t3"], data["t3"]);

            //fields to change
            newObject.Data["t3"] = "success";
            newObject.Data["t2"] = "qapla";

            //update
            repo.Update(newObject);

            //retrieve
            var newerObject = repo.Retrieve(objectId);

            //check the changes have been made
            Assert.AreEqual(newerObject.Id, objectId);
            Assert.AreEqual(newerObject.Collection.Name, CollectionName);
            Assert.AreEqual(newerObject.Data["t1"], data["t1"]);
            Assert.AreEqual(newerObject.Data["t2"], "qapla");
            Assert.AreEqual(newerObject.Data["t3"], "success");
        }

        [TestMethod]
        public void HasFieldReturnsTrueForColAndIdAutomatically()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //insert
            var objectId = repo.Create(data);

            //check if has col or id
            var hasId = repo.HasField(objectId, "_id");
            var hasCol = repo.HasField(objectId, "_col");

            //verifiy
            Assert.IsTrue(hasId);
            Assert.IsTrue(hasCol);
        }

        [TestMethod]
        public void HasFieldReturnsCorrectAnswerForNormalFields()
        {
            //get repo
            var repo = GetRepositoryForExistingCollectionWithTypes();

            //testdata
            var data = new Dictionary<string, object>();
            data["t1"] = "testdata1";
            data["t2"] = "testdata2";
            data["t3"] = "testdata3";

            //insert
            var objectId = repo.Create(data);

            //check for existing fields
            var result1 = repo.HasField(objectId, "t1");
            var result2 = repo.HasField(objectId, "bla");

            //check
            Assert.IsTrue(result1);
            Assert.IsFalse(result2);
        }

        #region Constructor Tests

        [TestMethod]
        [ExpectedException(typeof(NoSuchCollectionException))]
        public void GetRepositoryShouldThrowNoSuchCollectionExpectionIfNoCollectionExists()
        {
            TestHarness.ResetDatabase();
            var dataSource = TestHarness.DataSource;

            var repo = new ScienceRepository(dataSource, "dosentExist");
        }

        [TestMethod]
        public void GetRepositoryShouldPassCollectionNameToRepositoryObject()
        {
            TestHarness.ResetDatabase();
            var dataSource = TestHarness.DataSource;

            var scienceCollection = new ScienceCollection
            {
                Index = 1,
                CreatedBy = "testuser",
                CreatedOn = new DateTime(1985, 5, 23),
                Description = "test collection",
                Name = "test1"
            };

            scienceCollection = dataSource.AddCollection(scienceCollection);

            var repo = new ScienceRepository(dataSource, scienceCollection.Name);

            Assert.AreEqual(repo.CollectionName, scienceCollection.Name);
        }

        #endregion
    }
}